home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / DefaultCaret.java < prev    next >
Text File  |  1998-06-30  |  21KB  |  779 lines

  1. /*
  2.  * @(#)DefaultCaret.java    1.52 98/04/09
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.awt.*;
  23. import java.awt.event.*;
  24. import java.beans.*;
  25. import java.awt.event.ActionEvent;
  26. import java.awt.event.ActionListener;
  27. import java.io.*;
  28. import com.sun.java.swing.*;
  29. import com.sun.java.swing.event.*;
  30. import com.sun.java.swing.plaf.*;
  31.  
  32. /**
  33.  * An implementation of Caret for a view that maps over
  34.  * the entire portion of the model represented (i.e. there are no
  35.  * holes in the area represented) and renders the insert position
  36.  * as a vertical line.
  37.  *
  38.  * The foreground color of the component is the color of the caret
  39.  * and the background color of the component is the color of the
  40.  * selections made by moving the caret.  The Highlighter implementation
  41.  * of the associated UI is used to actually render the selection.
  42.  * <p>
  43.  * Warning: serialized objects of this class will not be compatible with
  44.  * future swing releases.  The current serialization support is appropriate 
  45.  * for short term storage or RMI between Swing1.0 applications.  It will
  46.  * not be possible to load serialized Swing1.0 objects with future releases
  47.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  48.  * baseline for the serialized form of Swing objects.
  49.  *
  50.  * @author  Timothy Prinzing
  51.  * @version 1.52 04/09/98
  52.  * @see     Caret
  53.  */
  54. public class DefaultCaret implements Caret, Serializable, FocusListener, MouseListener, MouseMotionListener {
  55.  
  56.     /**
  57.      * Constructs a default caret.
  58.      */
  59.     public DefaultCaret() {
  60.     }
  61.  
  62.     /**
  63.      * Gets the editor component that this caret is for.
  64.      *
  65.      * @return the component
  66.      */
  67.     protected final JTextComponent getComponent() {
  68.     return component;
  69.     }
  70.  
  71.     /**
  72.      * Damages the area surrounding the caret to cause
  73.      * it to be repainted.  If paint() is reimplemented,
  74.      * this method should also be reimplemented.
  75.      *
  76.      * @param r  the current location of the caret
  77.      * @see #paint
  78.      */
  79.     protected void damage(Rectangle r) {
  80.     if (r != null) {
  81.         component.repaint(r.x - 1, r.y, 3, r.height);
  82.     }
  83.     }
  84.  
  85.     /**
  86.      * Scrolls the associated view (if necessary) to make
  87.      * the caret visible.  Since how this should be done
  88.      * is somewhat of a policy, this method can be 
  89.      * reimplemented to change the behavior.  By default
  90.      * the scrollRectToVisible method is called on the
  91.      * associated component.
  92.      *
  93.      * @param nloc the new position to scroll to
  94.      */
  95.     protected void adjustVisibility(Rectangle nloc) {
  96.     SwingUtilities.invokeLater(new SafeScroller(nloc));
  97.     }
  98.  
  99.     /**
  100.      * Gets the painter for the Highlighter.
  101.      *
  102.      * @return the painter
  103.      */
  104.     protected Highlighter.HighlightPainter getSelectionPainter() {
  105.     Highlighter.HighlightPainter p = new DefaultHighlighter.DefaultHighlightPainter(
  106.         component.getSelectionColor());
  107.     return p;
  108.     }
  109.  
  110.     /**
  111.      * Tries to set the position of the caret from
  112.      * the coordinates of a mouse event, using viewToModel().
  113.      *
  114.      * @param e the mouse event
  115.      */
  116.     protected void positionCaret(MouseEvent e) {
  117.         Point pt = new Point(e.getX(), e.getY());
  118.     int pos = component.viewToModel(pt);
  119.     if (pos >= 0) {
  120.         setDot(pos);
  121.  
  122.         // clear the prefferred caret position
  123.         // see: JCaret's UpAction/DownAction
  124.         setMagicCaretPosition(null);
  125.     }
  126.     }
  127.  
  128.     /**
  129.      * Tries to move the position of the caret from
  130.      * the coordinates of a mouse event, using viewToModel(). 
  131.      * This will cause a selection if the dot and mark
  132.      * are different.
  133.      *
  134.      * @param e the mouse event
  135.      */
  136.     protected void moveCaret(MouseEvent e) {
  137.         Point pt = new Point(e.getX(), e.getY());
  138.     int pos = component.viewToModel(pt);
  139.     if (pos >= 0) {
  140.         moveDot(pos);
  141.     }
  142.     }
  143.  
  144.     // --- FocusListener methods --------------------------
  145.  
  146.     /**
  147.      * Called when the component containing the caret gains
  148.      * focus.  This is implemented to set the caret to visible
  149.      * if the component is editable, and sets the selection
  150.      * to visible.
  151.      *
  152.      * @param e the focus event
  153.      * @see FocusListener#focusGained
  154.      */
  155.     public void focusGained(FocusEvent e) {
  156.     if (component.isEditable()) {
  157.         setVisible(true);
  158.     }
  159.     //setSelectionVisible(true);
  160.     }
  161.  
  162.     /**
  163.      * Called when the component containing the caret loses
  164.      * focus.  This is implemented to set the caret to visibility
  165.      * to false, and to set the selection visibility to false.
  166.      *
  167.      * @param e the focus event
  168.      * @see FocusListener#focusLost
  169.      */
  170.     public void focusLost(FocusEvent e) {
  171.     setVisible(false);
  172.     //setSelectionVisible(false);
  173.     }
  174.  
  175.     // --- MouseListener methods -----------------------------------
  176.     
  177.     /**
  178.      * Called when the mouse is clicked.  A double click selects a word,
  179.      * and a triple click the current line.
  180.      *
  181.      * @param e the mouse event
  182.      * @see MouseListener#mouseClicked
  183.      */
  184.     public void mouseClicked(MouseEvent e) {
  185.     if(e.getClickCount() == 2) {
  186.         Action a = new DefaultEditorKit.SelectWordAction();
  187.         a.actionPerformed(null);
  188.     } else if(e.getClickCount() == 3) {
  189.         Action a = new DefaultEditorKit.SelectLineAction();
  190.         a.actionPerformed(null);
  191.     } 
  192.     }
  193.  
  194.     /**
  195.      * Requests focus on the associated
  196.      * text component, and tries to set the cursor position.
  197.      *
  198.      * @param e the mouse event
  199.      * @see MouseListener#mousePressed
  200.      */
  201.     public void mousePressed(MouseEvent e) {
  202.     positionCaret(e);
  203.     if (component.isEnabled()) {
  204.         component.requestFocus();
  205.     }
  206.     }
  207.  
  208.     /**
  209.      * Called when the mouse is released.
  210.      *
  211.      * @param e the mouse event
  212.      * @see MouseListener#mouseReleased
  213.      */
  214.     public void mouseReleased(MouseEvent e) {
  215.     }
  216.  
  217.     /**
  218.      * Called when the mouse enters a region.
  219.      *
  220.      * @param e the mouse event
  221.      * @see MouseListener#mouseEntered
  222.      */
  223.     public void mouseEntered(MouseEvent e) {
  224.     }
  225.  
  226.     /**
  227.      * Called when the mouse exits a region.
  228.      *
  229.      * @param e the mouse event
  230.      * @see MouseListener#mouseExited
  231.      */
  232.     public void mouseExited(MouseEvent e) {
  233.     }
  234.  
  235.     // --- MouseMotionListener methods -------------------------
  236.  
  237.     /**
  238.      * Moves the caret position 
  239.      * according to the mouse pointer's current
  240.      * location.  This effectively extends the
  241.      * selection.
  242.      *
  243.      * @param e the mouse event
  244.      * @see MouseMotionListener#mouseDragged
  245.      */
  246.     public void mouseDragged(MouseEvent e) {
  247.     moveCaret(e);
  248.     }
  249.  
  250.     /**
  251.      * Called when the mouse is moved.
  252.      *
  253.      * @param e the mouse event
  254.      * @see MouseMotionListener#mouseMoved
  255.      */
  256.     public void mouseMoved(MouseEvent e) {
  257.     }
  258.  
  259.     // ---- Caret methods ---------------------------------
  260.  
  261.     /**
  262.      * Renders the caret as a vertical line.  If this is reimplemented
  263.      * the damage method should also be reimplemented as it assumes the
  264.      * shape of the caret is a vertical line.  Sets the caret color to
  265.      * the value returned by getCaretColor().
  266.      *
  267.      * @param g the graphics context
  268.      * @see #damage
  269.      */
  270.     public void paint(Graphics g) {
  271.     if(isVisible()) {
  272.         try {
  273.         TextUI mapper = component.getUI();
  274.         Rectangle r = mapper.modelToView(dot);
  275.         g.setColor(component.getCaretColor());
  276.         g.drawLine(r.x, r.y, r.x, r.y + r.height - 1);
  277.         } catch (BadLocationException e) {
  278.         // can't render I guess
  279.         //System.err.println("Can't render cursor");
  280.         }
  281.     }
  282.     }
  283.     
  284.     /**
  285.      * Called when the UI is being installed into the
  286.      * interface of a JTextComponent.  This can be used
  287.      * to gain access to the model that is being navigated
  288.      * by the implementation of this interface.  Sets the dot
  289.      * and mark to 0, and establishes document, property change,
  290.      * focus, mouse, and mouse motion listeners.
  291.      *
  292.      * @param c the component
  293.      * @see Caret#install
  294.      */
  295.     public void install(JTextComponent c) {
  296.     component = c;
  297.     Document doc = c.getDocument();
  298.     dot = mark = 0;
  299.     if (doc != null) {
  300.         doc.addDocumentListener(updateHandler);
  301.     }
  302.     c.addPropertyChangeListener(updateHandler);
  303.     c.addFocusListener(this);
  304.     c.addMouseListener(this);
  305.     c.addMouseMotionListener(this);
  306.     }
  307.  
  308.     /**
  309.      * Called when the UI is being removed from the
  310.      * interface of a JTextComponent.  This is used to
  311.      * unregister any listeners that were attached.
  312.      *
  313.      * @param c the component
  314.      * @see Caret#deinstall
  315.      */
  316.     public void deinstall(JTextComponent c) {
  317.     c.removeMouseListener(this);
  318.     c.removeMouseMotionListener(this);
  319.     c.removeFocusListener(this);
  320.     c.removePropertyChangeListener(updateHandler);
  321.     Document doc = c.getDocument();
  322.     if (doc != null) {
  323.         doc.removeDocumentListener(updateHandler);
  324.     }
  325.     component = null;
  326.     if (flasher != null) {
  327.         flasher.stop();
  328.     }
  329.     }
  330.  
  331.     /**
  332.      * Adds a listener to track whenever the caret position has
  333.      * been changed.
  334.      *
  335.      * @param l the listener
  336.      * @see Caret#addChangeListener
  337.      */
  338.     public void addChangeListener(ChangeListener l) {
  339.     listenerList.add(ChangeListener.class, l);
  340.     }
  341.     
  342.     /**
  343.      * Removes a listener that was tracking caret position changes.
  344.      *
  345.      * @param l the listener
  346.      * @see Caret#removeChangeListener
  347.      */
  348.     public void removeChangeListener(ChangeListener l) {
  349.     listenerList.remove(ChangeListener.class, l);
  350.     }
  351.  
  352.     /**
  353.      * Notifies all listeners that have registered interest for
  354.      * notification on this event type.  The event instance 
  355.      * is lazily created using the parameters passed into 
  356.      * the fire method.  The listener list is processed last to first.
  357.      *
  358.      * @see EventListenerList
  359.      */
  360.     protected void fireStateChanged() {
  361.     // Guaranteed to return a non-null array
  362.     Object[] listeners = listenerList.getListenerList();
  363.     // Process the listeners last to first, notifying
  364.     // those that are interested in this event
  365.     for (int i = listeners.length-2; i>=0; i-=2) {
  366.         if (listeners[i]==ChangeListener.class) {
  367.         // Lazily create the event:
  368.         if (changeEvent == null)
  369.             changeEvent = new ChangeEvent(this);
  370.         ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
  371.         }           
  372.     }
  373.     }    
  374.  
  375.     /**
  376.      * Changes the selection visibility.
  377.      *
  378.      * @param vis the new visibility
  379.      */
  380.     public void setSelectionVisible(boolean vis) {
  381.     if (vis) {
  382.         // show
  383.         if ((selectionTag == null) && (dot != mark)) {
  384.         Highlighter h = component.getHighlighter();
  385.         int p0 = Math.min(dot, mark);
  386.         int p1 = Math.max(dot, mark);
  387.         Highlighter.HighlightPainter p = getSelectionPainter();
  388.         try {
  389.             selectionTag = h.addHighlight(p0, p1, p);
  390.         } catch (BadLocationException bl) {
  391.             selectionTag = null;
  392.         }
  393.         }
  394.     } else {
  395.         // hide
  396.         if (selectionTag != null) {
  397.         Highlighter h = component.getHighlighter();
  398.         h.removeHighlight(selectionTag);
  399.         selectionTag = null;
  400.         }
  401.     }
  402.     }
  403.  
  404.     /**
  405.      * Checks whether the current selection is visible.
  406.      *
  407.      * @return true if the selection is visible
  408.      */
  409.     public boolean isSelectionVisible() {
  410.     return (selectionTag != null);
  411.     }
  412.  
  413.     /**
  414.      * Determines if the caret is currently visible.
  415.      *
  416.      * @return true if visible else false
  417.      * @see Caret#isVisible
  418.      */
  419.     public boolean isVisible() {
  420.         return visible;
  421.     }
  422.  
  423.     /**
  424.      * Sets the caret visibility, and repaints the caret.
  425.      *
  426.      * @param e the visibility specifier
  427.      * @see Caret#setVisible
  428.      */
  429.     public void setVisible(boolean e) {
  430.     TextUI mapper = component.getUI();
  431.     Document doc = component.getDocument();
  432.         if ((visible != e) && (doc != null) && (mapper != null)) {
  433.         // repaint the caret
  434.         try {
  435.         Rectangle loc = mapper.modelToView(dot);
  436.         damage(loc);
  437.         } catch (BadLocationException badloc) {
  438.         // hmm... not legally positioned
  439.         }
  440.         }
  441.         visible = e;
  442.  
  443.     if (flasher != null) {
  444.         if (visible) {
  445.         flasher.start();
  446.         } else {
  447.         flasher.stop();
  448.         }
  449.     }
  450.     }
  451.  
  452.     /**
  453.      * Sets the caret blink rate.
  454.      *
  455.      * @param rate the rate in milliseconds, 0 to stop blinking
  456.      * @see Caret#setBlinkRate
  457.      */
  458.     public void setBlinkRate(int rate) {
  459.     if (rate != 0) {
  460.         if (flasher == null) {
  461.         flasher = new Timer(rate, updateHandler);
  462.         }
  463.         flasher.setDelay(rate);
  464.     } else {
  465.         if (flasher != null) {
  466.         flasher.stop();
  467.         flasher.removeActionListener(updateHandler);
  468.         flasher = null;
  469.         }
  470.     }
  471.     }
  472.  
  473.     /**
  474.      * Gets the caret blink rate.
  475.      *
  476.      * @returns the delay in milliseconds.  If this is
  477.      *  zero the caret will not blink.
  478.      * @see Caret#getBlinkRate
  479.      */
  480.     public int getBlinkRate() {
  481.     return (flasher == null) ? 0 : flasher.getDelay();
  482.     }
  483.  
  484.     /**
  485.      * Fetches the current position of the caret.
  486.      *
  487.      * @return the position >= 0
  488.      * @see Caret#getDot
  489.      */
  490.     public int getDot() {
  491.         return dot;
  492.     }
  493.  
  494.     /**
  495.      * Fetches the current position of the mark.  If there is a selection,
  496.      * the dot and mark will not be the same.
  497.      *
  498.      * @return the position >= 0
  499.      * @see Caret#getMark
  500.      */
  501.     public int getMark() {
  502.         return mark;
  503.     }
  504.  
  505.     /**
  506.      * Sets the caret position and mark to some position.  This
  507.      * implicitly sets the selection range to zero.
  508.      *
  509.      * @param dot the position >= 0
  510.      * @see Caret#setDot
  511.      */
  512.     public void setDot(int dot) {
  513.     // move dot, if it changed
  514.     Document doc = component.getDocument();
  515.     if (doc != null) {
  516.         dot = Math.min(dot, doc.getLength());
  517.     }
  518.     dot = Math.max(dot, 0);
  519.     mark = dot;
  520.     if (this.dot != dot || selectionTag != null) {
  521.         changeCaretPosition(dot);
  522.     }
  523.     if (selectionTag != null) {
  524.         Highlighter h = component.getHighlighter();
  525.         h.removeHighlight(selectionTag);
  526.         selectionTag = null;
  527.     }
  528.     }
  529.  
  530.     /**
  531.      * Moves the caret position to some other position.
  532.      *
  533.      * @param dot the position >= 0
  534.      * @see Caret#moveDot
  535.      */
  536.     public void moveDot(int dot) {
  537.     if (dot != this.dot) {
  538.         changeCaretPosition(dot);
  539.         Highlighter h = component.getHighlighter();
  540.         int p0 = Math.min(dot, mark);
  541.         int p1 = Math.max(dot, mark);
  542.         try {
  543.         if (selectionTag != null) {
  544.             h.changeHighlight(selectionTag, p0, p1);
  545.         } else {
  546.             Highlighter.HighlightPainter p = getSelectionPainter();
  547.             selectionTag = h.addHighlight(p0, p1, p);
  548.         }
  549.         } catch (BadLocationException e) {
  550.         throw new StateInvariantError("Bad caret position");
  551.         }
  552.     }
  553.     }
  554.  
  555.     // ---- local methods --------------------------------------------
  556.  
  557.     /**
  558.      * Sets the caret position (dot) to a new location.  This
  559.      * causes the old and new location to be repainted.  It
  560.      * also makes sure that the caret is within the visible 
  561.      * region of the view, if the view is scrollable.
  562.      */
  563.     void changeCaretPosition(int dot) {
  564.     TextUI mapper = component.getUI();
  565.     Document doc = component.getDocument();
  566.  
  567.     if ((mapper != null) && (doc != null)) {
  568.         // repaint the old position
  569.         Rectangle oldLoc;
  570.         try {
  571.         oldLoc = mapper.modelToView(this.dot);
  572.         damage(oldLoc);
  573.         } catch (BadLocationException e) {
  574.         oldLoc = null;
  575.         }
  576.  
  577.         // set the new value of dot
  578.         this.dot = dot;
  579.  
  580.         // determine the new location and scroll if
  581.         // not visible.
  582.         Rectangle newLoc;
  583.         try {
  584.         newLoc = mapper.modelToView(this.dot);
  585.         } catch (BadLocationException e) {
  586.         newLoc = null;
  587.         }
  588.             if (newLoc != null) {
  589.         adjustVisibility(newLoc);
  590.         }
  591.  
  592.         // repaint the new position
  593.         damage(newLoc);
  594.  
  595.         // notify listeners that the caret moved
  596.         fireStateChanged();
  597.     }
  598.     }
  599.  
  600.     /**
  601.      * Saves the current caret position.  This is used when 
  602.      * caret up/down actions occur, moving between lines
  603.      * that have uneven end positions.
  604.      *
  605.      * @param p the position
  606.      * @see #getMagicCaretPosition
  607.      * @see UpAction
  608.      * @see DownAction
  609.      */
  610.     public void setMagicCaretPosition(Point p) {
  611.     magicCaretPosition = p;
  612.     }
  613.     
  614.     /**
  615.      * Gets the saved caret position.
  616.      *
  617.      * @return the position
  618.      * see #setMagicCaretPosition
  619.      */
  620.     public Point getMagicCaretPosition() {
  621.     return magicCaretPosition;
  622.     }
  623.     
  624.     // --- serialization ---------------------------------------------
  625.  
  626.     private void readObject(ObjectInputStream s)
  627.       throws ClassNotFoundException, IOException 
  628.     {
  629.     s.defaultReadObject();
  630.     updateHandler = new UpdateHandler();
  631.     }
  632.  
  633.     // ---- member variables ------------------------------------------
  634.  
  635.     /**
  636.      * The event listener list.
  637.      */
  638.     protected EventListenerList listenerList = new EventListenerList();
  639.  
  640.     /**
  641.      * The change event for the model.
  642.      * Only one ChangeEvent is needed per model instance since the
  643.      * event's only (read-only) state is the source property.  The source
  644.      * of events generated here is always "this".
  645.      */
  646.     protected ChangeEvent changeEvent = null;
  647.  
  648.     // package-private to avoid inner classes private member
  649.     // access bug
  650.     JTextComponent component;
  651.     boolean visible;
  652.     int dot;
  653.     int mark;
  654.     Object selectionTag;
  655.     Timer flasher;
  656.     Point magicCaretPosition;
  657.     transient UpdateHandler updateHandler = new UpdateHandler();
  658.  
  659.     class SafeScroller implements Runnable {
  660.     
  661.     SafeScroller(Rectangle r) {
  662.         this.r = r;
  663.     }
  664.  
  665.     public void run() {
  666.         component.scrollRectToVisible(r);
  667.     }
  668.  
  669.     Rectangle r;
  670.     }
  671.  
  672.     class UpdateHandler implements PropertyChangeListener, DocumentListener, ActionListener {
  673.  
  674.     // --- ActionListener methods ----------------------------------
  675.     
  676.     /**
  677.      * Invoked when the blink timer fires.
  678.      *
  679.      * @param e the action event
  680.      */
  681.         public void actionPerformed(ActionEvent e) {
  682.         visible = !visible;
  683.         Rectangle loc;
  684.         try {
  685.         TextUI mapper = component.getUI();
  686.         loc = mapper.modelToView(dot);
  687.         damage(loc);
  688.         } catch (BadLocationException bl) {
  689.         // hmm....
  690.         }
  691.     }
  692.     
  693.     // --- DocumentListener methods --------------------------------
  694.  
  695.     /**
  696.      * Updates the dot and mark if they were changed by
  697.      * the insertion.
  698.      *
  699.      * @param e the document event
  700.      * @see DocumentListener#insertUpdate
  701.      */
  702.         public void insertUpdate(DocumentEvent e) {
  703.         int adjust = 0;
  704.         int offset = e.getOffset();
  705.         int length = e.getLength();
  706.         if (dot >= offset) {
  707.         adjust = length;
  708.         }
  709.         if (mark >= offset) {
  710.         mark += length;
  711.         }
  712.         
  713.         if (adjust != 0) {
  714.         changeCaretPosition(dot + adjust);
  715.         }
  716.     }
  717.  
  718.     /**
  719.      * Updates the dot and mark if they were changed
  720.      * by the removal.
  721.      *
  722.      * @param e the document event
  723.      * @see DocumentListener#removeUpdate
  724.      */
  725.         public void removeUpdate(DocumentEvent e) {
  726.         int adjust = 0;
  727.         int offs0 = e.getOffset();
  728.         int offs1 = offs0 + e.getLength();
  729.         if (dot >= offs1) {
  730.         adjust = offs1 - offs0;
  731.         } else if (dot >= offs0) {
  732.         adjust = dot - offs0;
  733.         }
  734.         if (mark >= offs1) {
  735.         mark -= offs1 - offs0;
  736.         } else if (mark >= offs0) {
  737.         mark = offs0;
  738.         }
  739.     
  740.         if (mark == (dot - adjust)) {
  741.         setDot(dot - adjust);
  742.         } else {
  743.         changeCaretPosition(dot - adjust);
  744.         }
  745.     }
  746.  
  747.     /**
  748.      * Gives notification that an attribute or set of attributes changed.
  749.      *
  750.      * @param e the document event
  751.      * @see DocumentListener#changedUpdate
  752.      */
  753.         public void changedUpdate(DocumentEvent e) {
  754.     }
  755.  
  756.     // --- PropertyChangeListener methods -----------------------
  757.  
  758.     /**
  759.      * This method gets called when a bound property is changed.
  760.      * We are looking for document changes on the editor.
  761.      */
  762.     public void propertyChange(PropertyChangeEvent evt) {
  763.         Object oldValue = evt.getOldValue();
  764.         Object newValue = evt.getNewValue();
  765.         if ((oldValue instanceof Document) || (newValue instanceof Document)) {
  766.         setDot(0);
  767.         if (oldValue != null) {
  768.             ((Document)oldValue).removeDocumentListener(this);
  769.         }
  770.         if (newValue != null) {
  771.             ((Document)newValue).addDocumentListener(this);
  772.         }
  773.         }
  774.     }
  775.  
  776.     }
  777. }
  778.  
  779.